import flask
import timemaker as tm
import time
from hashlib import sha1
import timeutils

app = flask.Flask(__name__)
app.secret_key = '\t\xf6u\xcf:c\xa3\xfd\xc5\xd5\xc2a\xd4\x1f\xd0Y`be/\xa2P\x12a'
tm.connect()


def resources():
	return {"bootstrap_css" : flask.url_for('static', filename='resources/css/bootstrap.min.css'),
			"framewarp_css" : flask.url_for('static', filename='resources/css/framewarp.css'),
			"utils_css" : flask.url_for('static', filename='resources/css/utils.css'),
			"cloud_css" : flask.url_for('static', filename='resources/css/jqcloud.css'),

			"jquery_js" : flask.url_for('static', filename='resources/js/jquery-1.8.3.min.js'),
			"bootstrap_js" : flask.url_for('static', filename='resources/js/bootstrap.min.js'),
			"japp_js" : flask.url_for('static', filename='resources/js/jquerypp.custom.js'),
			"utils_js" : flask.url_for('static', filename='resources/js/utils.js'),
			"framewarp_js" : flask.url_for('static', filename='resources/js/framewarp.js'),
			"cloud_js" : flask.url_for('static', filename='resources/js/jqcloud-1.0.2.min.js')
			}

@app.route('/', methods = ['POST', 'GET'])
def index():
	state = flask.request.args.get('ctype', '')
	stab = flask.request.args.get('tab', '')
	if not state:
		state = 3
	else:
		state = int(state)
	if not stab:
		stab = 0
	else:
		stab = int(stab)

	login_text = flask.Markup('<a href="#" class="navbar-link" id="login">Log In</a>')

	tabs = []
	tids = []
	actv = []
	seen = []
	unseen = []
	tem_id = None
	cat_id = ''

	priv_data = ''
	priv_state = 'You are not logged in'
	priv_num = 0

	user = ''
	post_content = ''

	if 'username' in flask.session:
		user = flask.session['username']
	elif flask.request.cookies.get('username'):
		user = flask.request.cookies.get('username')
		flask.session['username'] = user
	if user:
		#login
		login_text = flask.Markup('Logged in as %s (<a href="logout" class="navbar-link" id="logout">Log Out?</a>)' % (user))
		####################################categories********************************
		tuser = tm.User.select(username = user)[0]
		if 0 < state < 4:
			cats = tuser.get_categories(state)
		elif 3 < state < 7:
			cats = tuser.get_projects(state - 3)
		else:
			cats = tuser.get_categories()
		tabs = [c.name for c in cats]
		try:
			current = cats[stab]
			if tuser in current.owners:
				priv_state = flask.Markup('<strong>You are an owner</strong>')
				priv_num = 100
			elif tuser in current.editors:
				priv_state = flask.Markup('<strong>You are an editor</strong>')
				priv_num = 66
			elif tuser in current.viewers:
				priv_state = flask.Markup('<strong>You are a viewer</strong>')
				priv_num = 33
			if current.owners:
				priv_data += flask.Markup('<strong>Owners: </strong>' + ', '.join([u.username for u in current.owners]) + '<br>')
			if current.editors:
				priv_data += flask.Markup('<strong>Editors: </strong>' + ', '.join([u.username for u in current.editors]) + '<br>')
			if current.viewers:
				priv_data += flask.Markup('<strong>Viewers: </strong>' + ', '.join([u.username for u in current.viewers]) + '<br>')
			#########################################################################################################################
			cat_id = current.id
			flask.session['cat_id'] = cat_id
			tids = [{'name':t.title, 'id' : t.id} for t in current.templates]
			if len(tids):
				tem_id = tids[0]['id']
			post_content = flask.Markup(current.templates[0].content)
			
		except IndexError:
			cat_id = 0

		#################Notifications###################
		unseen = [n.message for n in tm.Notification.select(user = tuser, seen = False)]
		seen = [n.message for n in tm.Notification.select(user = tuser, seen = True)]
		unseen.reverse()
		seen.reverse()
		if len(seen) > 3:
			seen = seen[-3:]
		for chl in tm.Challenge.select(user = tuser, accepted = True):
			if chl.date > time.time():
				actv.append(flask.Markup("Issued by: %s, concerning '%s'<br>%d points remaining until %s.<hr>"%(chl.sender, chl.category.name, chl.target, chl.deadline)))
			else:
				tm.Notification(user = tuser, message = "You have failed %s's challenge concerning '%s'..."%(chl.sender, chl.category.name))
				tm.Notification(user = tm.User.find(chl.sender), message = "%s has failed your challenge concerning '%s'..."%(tuser.username, chl.category.name))
				chl.delete()
		tm.commit()

	return flask.render_template('index.html', login_text = login_text, tabs = tabs, cat_id = cat_id, post_content = post_content,
												priv_data = priv_data, priv_state = priv_state, priv_num = priv_num,
												state = state, stab = stab, user = user, tids = tids, tem_id = tem_id,
												seen = seen, unseen = unseen,  actv = actv, **resources())

@app.route('/all_seen/')
def make_seen():
	user = tm.User.find(flask.session['username'])
	for n in tm.Notification.select(user = user, seen = False):
		n.seen = True
	tm.commit()
	return """"""

@app.route('/share/', methods = ['POST', 'GET'])
def share():
	r = flask.request
	me = tm.User.find(flask.session['username'])
	if r.method == 'POST':
		f = dict([(x, r.form[x]) for x in r.form])
		users = set([x for x in f['added'].split(',') if x])
		for user in list(users):
			try:
				user = user.encode('utf8')
				user = tm.remove_control_chars(user)
				user = user.decode('utf8')
				tu = tm.User.find(user)
				cid = int(flask.session['cat_id'])
				c = tm.Category.select(id = cid)[0]
				sa = int(f['share_as'])
				me.share(c, tu, sa)
				print 'shared with', user
			except Exception, e:
				print str(e)
				continue
		tm.commit()
	return flask.redirect(flask.url_for('index'))

def get_tags(cat):
	tags = {}
	rel ={}
	for p in [x for x in cat.posts if x.priority > 0]:
		priority = p.priority
		for t in p.tags:
			if t.tag not in tags:
				tags[t.tag] = (t.occurs, priority)
				rel[t.tag] = 1
			else:
				tags[t.tag] = (tags[t.tag][0] + t.occurs, tags[t.tag][1] + priority)
				rel[t.tag] += 1
	ntags = []
	for t in tags:
		ntags.append({"text" : t, "weight" : tags[t][0], "priority" : tags[t][1] / rel[t]})
	stags = sorted(ntags, cmp = lambda x, y: cmp(x["weight"], y['weight']), reverse = True)
	return stags[:50]

@app.route('/tags.html/')
def tags():
	cat_id = flask.request.args.get('cat', '')
	tags = []
	if cat_id:
		current = tm.Category.select(id = int(cat_id))[0]
		tags = get_tags(current)
	return flask.render_template('tags.html', tags = tags, cat_id = cat_id, **resources())


@app.route('/logout/')
def logout():
	try:
		flask.session.__delitem__('username')
	except KeyError:
		pass
	res = flask.make_response(flask.redirect(flask.url_for('index')))
	res.delete_cookie('username')
	return res

@app.route('/login.html/')
def login():
	leave = ('username' in flask.session) or (flask.request.cookies.get('username'))
	msg = flask.get_flashed_messages()
	return flask.render_template('login.html', leave = leave, msg = msg, **resources())

@app.route('/login.html/try', methods = ['POST', 'GET'])
def try_login():
	r = flask.request
	res = flask.make_response(flask.redirect(flask.url_for('login')))
	if r.method == "POST":
		user = r.form['user']
		hpass = r.form['password']
		u = tm.User.select(username = user, pass_hash = hpass)
		if u:
			if 'remember' in r.form and r.form['remember'] == 'remember-me':
				res.set_cookie('username', user)
			flask.session['username'] = user
		else:
			flask.flash('Wrong username or password...')
	return res

@app.route('/challenge.html/<int:catid>/')
def challenge(catid):
	leave = "issued" in flask.session
	if leave:
		flask.session.__delitem__('issued')
	msg = flask.get_flashed_messages()
	users = [u.username for u in tm.Category.select(id = catid)[0].get_editors()]
	return flask.render_template('challenge.html', leave = leave, msg = msg, users = users, **resources())

@app.route('/challenge.html/<int:catid>/try', methods = ['POST', 'GET'])
def try_challenge(catid):
	r = flask.request
	res = flask.make_response(flask.redirect('/challenge.html/' + str(catid)))
	if r.method == "POST":
		target = r.form['target']
		deadline = r.form['deadline']
		try:
			target = int(target)
		except Exception:
			flask.flash('Target point value must be a number!')
			return res
		try:
			temp, ddl = timeutils.tryslate(deadline)
		except TypeError:
			flask.flash('Deadline must be in a known format!')
			return res
		try:
			assert temp > time.time()
		except Exception:
			flask.flash('Deadline must be set in the future!')
			return res
		flask.session['issued'] = True
		f = r.form
		df = dict([(x, f[x]) for x in f])
		df.__delitem__('target')
		df.__delitem__('deadline')
		for k in df:
			if df[k] == k:
				tuser = tm.User.find(flask.session['username'])
				tuser.issue_challenge(k, catid, ddl, target)
		tm.commit()
	return res

@app.route('/new_post.html/<int:catid>/<int:template_id>/', methods = ['POST', 'GET'])
def new_post(catid, template_id):
	r = flask.request
	if r.method == "POST":
		cat = tm.Category.select(id = catid)[0]
		f = r.form
		df = dict([(x, f[x]) for x in f])
		cat.create_post(flask.session['username'], df, template_id)
		tm.commit()
	return flask.redirect(flask.url_for('index'))

@app.route('/post.html/<int:template_id>/')
def post(template_id):
	r = flask.request
	return_to = r.args.get('ret', '')
	updated = r.args.get('updated', '')
	pid = r.args.get('pid', '')
	items = []
	post_content = ''
	if not updated:
		post_content = flask.Markup(tm.Template.select(id = template_id)[0].content)
		if pid:
			pid = int(pid)
			post = tm.Post.select(id = pid)[0]
			rendered = post.rendered()
			items = [{"name" : k, "value" : rendered.__getattribute__(k)} for k in rendered.__dict__]
	return flask.render_template('new_post.html', pid = pid, ret = return_to, items = items, updated = updated,
									post_content = post_content, **resources())

@app.route('/poster/<int:template_id>/', methods = ['POST'])
def poster(template_id):
	r = flask.request
	user = tm.User.find(flask.session['username'])
	pid = r.args.get('pid', '')
	cid = r.args.get('cid', '')
	ret = r.args.get('ret', '')#ret means it's an update!!!!
	f = r.form
	df = dict([(x, f[x]) for x in f])
	if pid:
		pid = int(pid)
		post = tm.Post.select(id = pid)[0]
		post.edit(user, df)
	else:
		cat = tm.Category.select(id = flask.session['cat_id'])[0]
		cat.create_post(user, df, template_id)
	tm.commit()
	if ret:
		ret = ret.decode("hex")
		return flask.redirect(ret)
	return flask.redirect(flask.url_for('index'))
	#do some magic...


@app.route('/new_category.html/', methods = ['POST', 'GET'])
def new_category():
	leave = False
	r = flask.request
	if r.method == "POST":
		f = r.form
		u = tm.User.find(flask.session['username'])
		if f['type'] == 'cat':
			u.add_category(f['name'])
		elif f['type'] == 'proj':
			u.add_project(f['name'])
		tm.commit()
		leave = True
	return flask.render_template('new_category.html',leave =leave, **resources())

def list_posts(cat_id = '', tag = ''):
	user = tm.User.find(flask.session['username'])
	posts = []
	if cat_id:
		cat_id = int(cat_id)
		cat = tm.Category.select(id = cat_id)[0]
		if tag:
			tposts = cat.filter_by_tag(tag)
		else:
			tposts = cat.posts
		tposts = filter(lambda x: x.priority > 0, tposts)
		rposts = [p.rendered() for p in tposts]
        # from XML in the DB, to RenderedPost Object
		for rendered_post in rposts:
			post = tm.Post.select(id = rendered_post.id)[0] 
            # TODO still not from template
			posts.append({"title" : rendered_post.title, "description" : rendered_post.description, "priority" : rendered_post.priority,
						  "id" : rendered_post.id, "can_delete" : post.can_edit(user), "can_see" : post.can_see(user),
						  "template" : post.template_timeentity_id})
	return posts

@app.route('/finish/<int:pid>/')
def finish_post(pid):
	p = tm.Post.select(id = pid)[0]
	chl = tm.Challenge.select(user = tm.User.find(flask.session['username']), category = p.category)
	for c in chl:
		c.target -= p.priority
		if c.target < 1:
			tm.Notification(user = tm.User.find(c.sender), message = "%s has won your challenge concerning '%s'"%(flask.session['username'], p.category.name))
			c.delete()
	p.priority = 0
	tm.commit()
	return """"""

@app.route('/decline/<int:chid>/<int:nid>/')
def decline_challenge(chid, nid):
	chl = tm.Challenge.select(id = chid)[0]
	chl.decline()
	notif = tm.Notification.select(id = nid)[0]
	om = notif.message[:]
	notif.message = om[:om.index("<br")] + "<br>Challenge Declined..."
	tm.commit()
	return """"""

@app.route('/accept/<int:chid>/<int:nid>/')
def accept_challenge(chid, nid):
	chl = tm.Challenge.select(id = chid)[0]
	chl.accept()
	notif = tm.Notification.select(id = nid)[0]
	om = notif.message[:]
	notif.message = om[:om.index("<br")] + "<br>Challenge Accepted!"
	tm.commit()
	return flask.Markup("Issued by: %s, concerning '%s'<br>%d points remaining until %s.<hr>"%(chl.sender, chl.category.name, chl.target, chl.deadline))

@app.route('/basic_list.html/', methods = ['POST', 'GET'])
def basic():
	r = flask.request
	if r.method == "POST":
		f = r.form
		for p in tm.Post.select(id = int(f['post_id'])):
			p.delete()
		tm.commit()
	cat_id = flask.request.args.get('cat_id', '')
	tag = flask.request.args.get('tag', '')
	posts = list_posts(cat_id, tag)
	return flask.render_template('basic_list.html', posts = posts, **resources())

@app.route('/prioritised_list.html/', methods = ['POST', 'GET'])
def prioritised():
	r = flask.request
	if r.method == "POST":
		f = r.form
		for p in tm.Post.select(id = int(f['post_id'])):
			p.delete()
		tm.commit()
	cat_id = flask.request.args.get('cat_id', '')
	tag = flask.request.args.get('tag', '')
	posts = list_posts(cat_id, tag)
	sposts = sorted(posts, cmp=lambda x, y: cmp(x['priority'], y['priority']), reverse = True)
	return flask.render_template('basic_list.html', posts = sposts, **resources())

if __name__ == '__main__':
	app.debug = True
	app.run(host = '0.0.0.0', port = 8080)

